/*
 * ThreadPool.cpp
 *
 * ThreadPool 类的实现文件。
 * 包含构造、析构、shutdown、size、workerLoop 等非模板成员实现。
 */

#include "ThreadPool.hpp"

/**
 * @brief 构造函数：初始化线程池并创建指定数量的工作线程。
 *        构造阶段完成线程启动，以便后续提交任务时无需再创建线程。
 *
 * @param threadCount 线程池中的工作线程数量，需大于 0。
 *
 * @throws std::invalid_argument 若 threadCount == 0，则抛出异常提醒调用方。
 */
ThreadPool::ThreadPool(std::size_t threadCount)
    : m_stop(false) { // 初始状态：线程池未停止
    if (threadCount == 0) {
        throw std::invalid_argument("ThreadPool size must be greater than zero.");
    }

    // 预留线程容器空间，避免在 emplace_back 时多次重新分配内存。
    m_workers.reserve(threadCount);

    // 按照给定数量创建工作线程，每个线程执行 workerLoop。
    for (std::size_t i = 0; i < threadCount; ++i) {
        m_workers.emplace_back([this, i] { workerLoop(i); });
        // 这里捕获 this 以访问成员函数与任务队列。
    }
}

/**
 * @brief 析构函数：自动关闭线程池（等待任务完成后退出）。
 *        若用户未显式调用 shutdown()，析构会在此执行，保证资源释放。
 */
ThreadPool::~ThreadPool() {
    shutdown();
}

/**
 * @brief 关闭线程池，可选择是否等待队列中剩余任务执行完毕。
 *
 * @param wait true：等待队列中任务执行完毕再退出；false：直接丢弃剩余任务。
 */
void ThreadPool::shutdown(bool wait) {
    bool expected = false;
    // 使用原子操作确保只执行一次停止逻辑。
    if (!m_stop.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
        return; // 若 m_stop 已为 true，表示已经关闭过，直接返回。
    }

    {
        // 在持锁状态下处理任务队列，确保线程安全。
        std::lock_guard<std::mutex> lock(m_queueMutex);
        if (!wait) {
            // 如果无需等待剩余任务，则直接清空队列，丢弃未执行的任务。
            std::queue<std::function<void()>> empty;
            std::swap(m_tasks, empty);
        }
    }

    // 唤醒所有工作线程，避免线程阻塞在等待条件变量。
    m_condition.notify_all();

    // 主动 join 所有工作线程，确保线程在退出前完成清理，避免资源泄漏。
    for (std::thread& worker : m_workers) {
        if (worker.joinable()) {
            worker.join();
        }
    }
}

/**
 * @brief 获取线程池中的工作线程数量。
 *
 * @return std::size_t 当前工作线程数量。
 */
std::size_t ThreadPool::size() const noexcept {
    return m_workers.size();
}

/**
 * @brief 工作线程执行函数：从任务队列中不断提取并执行任务，直到线程池停止。
 *
 * @param workerIndex 当前工作线程的索引，可用于日志或调试（此实现中未使用）。
 */
void ThreadPool::workerLoop(std::size_t /*workerIndex*/) noexcept {
    while (true) {
        std::function<void()> task;

        {
            // 独占锁保护任务队列，防止多个线程同时修改。
            std::unique_lock<std::mutex> lock(m_queueMutex);

            // 使用条件变量等待新任务或线程池被停止。
            // 当 m_tasks 非空或 m_stop 为 true 时唤醒。
            m_condition.wait(lock, [this] {
                return m_stop.load(std::memory_order_acquire) || !m_tasks.empty();
            });

            // 若线程池已停止且队列为空，则退出循环，结束线程。
            if (m_stop.load(std::memory_order_relaxed) && m_tasks.empty()) {
                return;
            }

            // 从队列取出一个任务进行执行。
            task = std::move(m_tasks.front());
            m_tasks.pop();
        }

        // 将任务执行放在锁外，以缩短锁持有时间，提高并发度。
        try {
            task();
        } catch (...) {
            // 捕捉任务执行中的异常，避免线程异常退出。
            // 异常会通过 std::future 在提交方线程中重新抛出。
            // 此处可增加日志记录以辅助调试。
        }
    }
}